#include "flash.h"

//清除扇区
//StartAddress:取值范围(0x08000000~0x0807FFFF)

//F407IGT6 1024k 11个扇区
uint32_t sectStartAddr[8]=
{
    ADDR_FLASH_SECTOR_0,//0
    ADDR_FLASH_SECTOR_1,//1
    ADDR_FLASH_SECTOR_2,//2
    ADDR_FLASH_SECTOR_3,//3
    ADDR_FLASH_SECTOR_4,//4
    ADDR_FLASH_SECTOR_5,//5
    ADDR_FLASH_SECTOR_6,//6
    ADDR_FLASH_SECTOR_7,//7
};

//获取Sector的编号
int get_sector_from_address(uint32_t address)
{
    int sect;
    if( address < ADDR_FLASH_SECTOR_0 || address >= ADDR_FLASH_SECTOR_8 )
        return -1;
    for( int i=0; i<8; i++ )
    {
        if( address >= sectStartAddr[i] && address < sectStartAddr[i+1] )
        {
            sect = i;
            break;
        }
    }
    return sect;
}

void mcu_flash_erase(uint32_t StartAddress)
{
    int sect = 0;
    HAL_FLASH_Unlock();//解锁
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                          FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);//清除一些错误标志

    sect = get_sector_from_address(StartAddress);//获取地址所在的扇区
    FLASH_Erase_Sector(sect,FLASH_VOLTAGE_RANGE_3);//擦除指定的闪存扇区(0~7)
    HAL_FLASH_Lock();//上锁
}

//读取指定地址的字(32位数据)
//faddr:读地址
//返回值:对应数据.
uint32_t WriteAddr;

uint32_t STM32_FLASH_ReadWord(uint32_t faddr)
{
  return *(__IO uint32_t*)faddr;
}

uint8_t mcu_flash_write(uint32_t addr, uint8_t *buffer, uint32_t length)
{
  FLASH_EraseInitTypeDef FlashEraseInit;
  HAL_StatusTypeDef FlashStatus = HAL_OK;
  uint32_t SectorError          = 0;
  uint32_t addrx                = 0;
  uint32_t endaddr              = 0;
  WriteAddr                     = addr;

  if( (WriteAddr<ADDR_FLASH_SECTOR_0) || (WriteAddr%4) || (WriteAddr>=ADDR_FLASH_SECTOR_8) )
  {
    return Addr_Error;	//错误地址
  }

  HAL_FLASH_Unlock();           // 解锁flash
  addrx   = WriteAddr;		// 写入起始地址
  endaddr = WriteAddr + length;	// 写入结束地址

  if( (addrx == ADDR_FLASH_SECTOR_0) || (addrx == ADDR_FLASH_SECTOR_1)|| (addrx == ADDR_FLASH_SECTOR_2) || (addrx == ADDR_FLASH_SECTOR_3)
     || (addrx == ADDR_FLASH_SECTOR_4) || (addrx == ADDR_FLASH_SECTOR_5) || (addrx == ADDR_FLASH_SECTOR_6) || (addrx == ADDR_FLASH_SECTOR_7) )
  {
    FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;             //扇区擦除
    FlashEraseInit.Sector    = get_sector_from_address( addrx );    //擦除的扇区
    FlashEraseInit.NbSectors = 1;                                   //擦除1个扇区
    FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;              //电压范围2.7-3.6
    if( HAL_FLASHEx_Erase( &FlashEraseInit,&SectorError ) != HAL_OK )
    {
      HAL_FLASH_Lock();     //flash上锁
      return Erase_Error;	//擦除错误
    }
  }
  FlashStatus = FLASH_WaitForLastOperation( FLASH_WAITETIME );         //等待操作完成
  if( FlashStatus == HAL_OK )
  {
    while( WriteAddr < endaddr )//写数据
    {
      if( HAL_FLASH_Program( FLASH_TYPEPROGRAM_BYTE,WriteAddr, *buffer ) != HAL_OK )
      {
        HAL_FLASH_Lock();       //flash上锁
        return Write_Error;	//写错误
      }
      WriteAddr++;
      buffer++;
    }
  }
  else
  {
    HAL_FLASH_Lock();       //flash上锁
    return Write_Error;
  }
  HAL_FLASH_Lock();           //flash上锁
  return Read_OK;
}

void mcu_flash_read( uint32_t addr, uint8_t *buffer, uint32_t length )
{
  uint32_t  i;
  for( i = 0; i < length; i++ )
  {
    buffer[i] = STM32_FLASH_ReadWord( addr );//读取4个字节.
    addr++;//偏移4个`字节.
  }
}
uint8_t get_process_status(void)
{
  return STM32_FLASH_ReadWord( SETTING_SECTOR_ADDR );
}
void copy_flash_bin_128kb( uint32_t sources_bin, uint32_t target_bin )
{
  uint32_t data = 0;
  uint32_t SectorError          = 0;
  char str[56];
  HAL_StatusTypeDef FlashStatus = HAL_OK;
  FLASH_EraseInitTypeDef FlashEraseInit;
  FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;             //扇区擦除
  FlashEraseInit.Sector    = get_sector_from_address( target_bin );    //擦除的扇区
  FlashEraseInit.NbSectors = 1;                                   //擦除1个扇区
  FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;              //电压范围2.7-3.6

  HAL_FLASH_Unlock();           // 解锁flash

  HAL_Delay(20);
  if( HAL_FLASHEx_Erase( &FlashEraseInit,&SectorError ) != HAL_OK )
  {
    uart_log("erase failure!\r\n");
    HAL_FLASH_Lock();         //flash上锁
  }
  FlashStatus = FLASH_WaitForLastOperation( FLASH_WAITETIME );         //等待操作完成if( FlashStatus == HAL_OK )

  sprintf(str, "flash status: %d\r\n", FlashStatus );
  uart_log( str );
  HAL_FLASH_Unlock();           // 解锁flash
  if( FlashStatus == HAL_OK )
  {
    for( uint32_t i = 0; i < 128 * 256; i++ )
    {
      data = STM32_FLASH_ReadWord( sources_bin + i * 4 );
      HAL_FLASH_Program( FLASH_TYPEPROGRAM_WORD,target_bin + i * 4, data );
    }
  }
  HAL_FLASH_Lock();           //flash上锁
}